package controller;

import dto.Request;
import dto.Response;
import service.DatabaseService;
import service.impl.DatabaseServiceImpl;
import utils.JsonUtils;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据库服务器
 * 支持多线程处理客户端连接
 */
@Slf4j
public class DatabaseServer {
    
    private final int port;
    private final DatabaseService databaseService;
    private ServerSocket serverSocket;
    private final ExecutorService threadPool;
    private final AtomicInteger clientCount;
    private volatile boolean running;
    
    public DatabaseServer(int port) {
        this.port = port;
        this.databaseService = DatabaseServiceImpl.getInstance();
        this.threadPool = Executors.newCachedThreadPool();
        this.clientCount = new AtomicInteger(0);
        this.running = false;
    }
    
    /**
     * 启动服务器
     */
    public void start() {
        try {
            serverSocket = new ServerSocket(port);
            running = true;
            log.info("数据库服务器启动成功，监听端口: {}", port);
            
            while (running) {
                Socket clientSocket = serverSocket.accept();
                int clientId = clientCount.incrementAndGet();
                log.info("客户端连接: {} (ID: {})", clientSocket.getInetAddress(), clientId);
                
                // 为每个客户端创建独立的处理线程
                threadPool.submit(new ClientHandler(clientSocket, clientId));
            }
        } catch (IOException e) {
            log.error("服务器启动失败: error={}", e.getMessage());
        } finally {
            stop();
        }
    }
    
    /**
     * 停止服务器
     */
    public void stop() {
        running = false;
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
            threadPool.shutdownNow();
            // 数据持久化
            if (databaseService instanceof service.impl.DatabaseServiceImpl) {
                ((service.impl.DatabaseServiceImpl) databaseService).saveDataToFile();
                ((service.impl.DatabaseServiceImpl) databaseService).saveCollectionsToFile();
            }
            log.info("数据库服务器已停止");
        } catch (IOException e) {
            log.error("关闭服务器失败: error={}", e.getMessage());
        }
    }
    
    /**
     * 客户端处理器（内部类）
     */
    private class ClientHandler implements Runnable {
        private final Socket clientSocket;
        private final int clientId;
        private ObjectInputStream inputStream;
        private ObjectOutputStream outputStream;
        
        public ClientHandler(Socket clientSocket, int clientId) {
            this.clientSocket = clientSocket;
            this.clientId = clientId;
        }
        
        @Override
        public void run() {
            try {
                inputStream = new ObjectInputStream(clientSocket.getInputStream());
                outputStream = new ObjectOutputStream(clientSocket.getOutputStream());
                
                log.info("客户端 {} 处理器启动", clientId);
                
                while (running && !clientSocket.isClosed()) {
                    Request request = (Request) inputStream.readObject();
                    if (request != null) {
                        Response response = processRequest(request);
                        outputStream.writeObject(response);
                        outputStream.flush();
                        outputStream.reset();
                    }
                }
            } catch (IOException e) {
                log.error("客户端 {} 连接异常: error={}", clientId, e.getMessage());
            } catch (ClassNotFoundException e) {
                log.error("客户端 {} 数据反序列化失败: error={}", clientId, e.getMessage());
            } finally {
                closeConnection();
            }
        }
        
        /**
         * 处理客户端请求
         */
        private Response processRequest(Request request) {
            long startTime = System.currentTimeMillis();
            Response response;
            
            try {
                log.debug("处理客户端 {} 请求: type={}, key={}", clientId, request.getType(), request.getKey());
                
                switch (request.getType()) {
                    case PUT:
                        response = handlePut(request);
                        break;
                    case GET:
                        response = handleGet(request);
                        break;
                    case UPDATE:
                        response = handleUpdate(request);
                        break;
                    case DELETE:
                        response = handleDelete(request);
                        break;
                    case CONTAINS_KEY:
                        response = handleContainsKey(request);
                        break;
                    case GET_ALL_KEYS:
                        response = handleGetAllKeys(request);
                        break;
                    case GET_ALL_KEY_VALUES:
                        response = handleGetAllKeyValues(request);
                        break;
                    case BATCH_PUT:
                        response = handleBatchPut(request);
                        break;
                    case BATCH_UPDATE:
                        response = handleBatchUpdate(request);
                        break;
                    case BATCH_DELETE:
                        response = handleBatchDelete(request);
                        break;
                    case CREATE_COLLECTION:
                        response = handleCreateCollection(request);
                        break;
                    case DELETE_COLLECTION:
                        response = handleDeleteCollection(request);
                        break;
                    case GET_COLLECTION:
                        response = handleGetCollection(request);
                        break;
                    case GET_ALL_COLLECTIONS:
                        response = handleGetAllCollections(request);
                        break;
                    case PUT_IN_COLLECTION:
                        response = handlePutInCollection(request);
                        break;
                    case GET_FROM_COLLECTION:
                        response = handleGetFromCollection(request);
                        break;
                    case DELETE_FROM_COLLECTION:
                        response = handleDeleteFromCollection(request);
                        break;
                    case GET_ALL_FROM_COLLECTION:
                        response = handleGetAllFromCollection(request);
                        break;
                    case CLEAR:
                        response = handleClear(request);
                        break;
                    case GET_STATISTICS:
                        response = handleGetStatistics(request);
                        break;
                    case PING:
                        response = Response.success("PONG");
                        break;
                    default:
                        response = Response.error("未知的请求类型: " + request.getType());
                }
                
                long executionTime = System.currentTimeMillis() - startTime;
                response.setRequestId(request.getRequestId());
                response.setExecutionTime(executionTime);
                
                log.debug("客户端 {} 请求处理完成: type={}, executionTime={}ms", 
                         clientId, request.getType(), executionTime);
                
            } catch (Exception e) {
                log.error("处理客户端 {} 请求失败: error={}", clientId, e.getMessage());
                response = Response.error("服务器内部错误: " + e.getMessage());
                response.setRequestId(request.getRequestId());
            }
            
            return response;
        }
        
        private boolean isMaster() {
            // 只适用于DatabaseServiceImpl
            if (databaseService instanceof service.impl.DatabaseServiceImpl) {
                try {
                    java.lang.reflect.Field f = service.impl.DatabaseServiceImpl.class.getDeclaredField("isMaster");
                    f.setAccessible(true);
                    return (boolean) f.get(databaseService);
                } catch (Exception e) {
                    return true; // 默认主节点
                }
            }
            return true;
        }
        
        private Response handlePut(Request request) {
            boolean allowWrite = isMaster() || request.isReplicated();
            if (!allowWrite) {
                return Response.error("从节点只读，拒绝写入");
            }
            boolean success = ((service.impl.DatabaseServiceImpl)databaseService).put(request.getKey(), request.getValue(), allowWrite);
            if (!success) {
                // 判断是否因为键已存在
                if (((service.impl.DatabaseServiceImpl)databaseService).containsKey(request.getKey())) {
                    return Response.error("存储失败，键已存在");
                } else {
                    return Response.error("存储失败");
                }
            }
            return Response.success("存储成功", request.getValue());
        }
        
        private Response handleGet(Request request) {
            // 只返回 value，不返回 KeyValue 对象
            Object value = databaseService.get(request.getKey(), Object.class);
            return value != null ?
                Response.success("获取成功", value) :
                Response.error("键不存在", request.getKey());
        }
        
        private Response handleUpdate(Request request) {
            boolean allowWrite = isMaster() || request.isReplicated();
            if (!allowWrite) {
                return Response.error("从节点只读，拒绝更新");
            }
            boolean success = ((service.impl.DatabaseServiceImpl)databaseService).update(request.getKey(), request.getValue(), allowWrite);
            if (!success) {
                if (!((service.impl.DatabaseServiceImpl)databaseService).containsKey(request.getKey())) {
                    return Response.error("更新失败，键不存在");
                } else {
                    return Response.error("更新失败");
                }
            }
            return Response.success("更新成功", request.getValue());
        }
        
        private Response handleDelete(Request request) {
            boolean allowWrite = isMaster() || request.isReplicated();
            if (!allowWrite) {
                return Response.error("从节点只读，拒绝删除");
            }
            boolean success = ((service.impl.DatabaseServiceImpl)databaseService).delete(request.getKey(), allowWrite);
            if (!success) {
                if (!((service.impl.DatabaseServiceImpl)databaseService).containsKey(request.getKey())) {
                    return Response.error("删除失败，键不存在");
                } else {
                    return Response.error("删除失败");
                }
            }
            return Response.success("删除成功");
        }
        
        private Response handleContainsKey(Request request) {
            boolean exists = databaseService.containsKey(request.getKey());
            return Response.success("查询完成", exists);
        }
        
        private Response handleGetAllKeys(Request request) {
            java.util.List<String> keys = databaseService.getAllKeys();
            return Response.success("获取所有键成功", keys);
        }
        
        private Response handleGetAllKeyValues(Request request) {
            try {
                Class<?> clazz = Class.forName(request.getValueType());
                java.util.List<?> keyValues = databaseService.getAllKeyValues(clazz);
                return Response.success("获取所有键值对成功", keyValues);
            } catch (ClassNotFoundException e) {
                return Response.error("类型转换失败: " + e.getMessage());
            }
        }
        
        // 批量操作处理
        private Response handleBatchPut(Request request) {
            boolean success = databaseService.batchPut(request.getBatchData());
            return success ? 
                Response.success("批量插入成功") : 
                Response.error("批量插入失败");
        }
        
        private Response handleBatchUpdate(Request request) {
            boolean success = databaseService.batchUpdate(request.getBatchData());
            return success ? 
                Response.success("批量更新成功") : 
                Response.error("批量更新失败");
        }
        
        private Response handleBatchDelete(Request request) {
            boolean success = databaseService.batchDelete(request.getBatchKeys());
            return success ? 
                Response.success("批量删除成功") : 
                Response.error("批量删除失败");
        }
        
        // 集合操作处理
        private Response handleCreateCollection(Request request) {
            boolean success = databaseService.createCollection(
                request.getCollectionName(), request.getCollectionDescription());
            return success ? 
                Response.success("创建集合成功") : 
                Response.error("创建集合失败，集合可能已存在");
        }
        
        private Response handleDeleteCollection(Request request) {
            boolean success = databaseService.deleteCollection(request.getCollectionName());
            return success ? 
                Response.success("删除集合成功") : 
                Response.error("删除集合失败，集合可能不存在");
        }
        
        private Response handleGetCollection(Request request) {
            Object collection = databaseService.getCollection(request.getCollectionName());
            return collection != null ? 
                Response.success("获取集合成功", collection) : 
                Response.error("集合不存在");
        }
        
        private Response handleGetAllCollections(Request request) {
            java.util.List<?> collections = databaseService.getAllCollections();
            return Response.success("获取所有集合成功", collections);
        }
        
        private Response handlePutInCollection(Request request) {
            boolean success = databaseService.putInCollection(
                request.getCollectionName(), request.getKey(), request.getValue());
            return success ? 
                Response.success("在集合中存储成功") : 
                Response.error("在集合中存储失败，集合可能不存在");
        }
        
        private Response handleGetFromCollection(Request request) {
            try {
                Class<?> clazz = Class.forName(request.getValueType());
                Object value = databaseService.getFromCollection(
                    request.getCollectionName(), request.getKey(), clazz);
                return value != null ? 
                    Response.success("从集合获取成功", value) : 
                    Response.error("从集合获取失败，键可能不存在");
            } catch (ClassNotFoundException e) {
                return Response.error("类型转换失败: " + e.getMessage());
            }
        }
        
        private Response handleDeleteFromCollection(Request request) {
            boolean success = databaseService.deleteFromCollection(
                request.getCollectionName(), request.getKey());
            return success ? 
                Response.success("从集合删除成功") : 
                Response.error("从集合删除失败，键可能不存在");
        }
        
        private Response handleGetAllFromCollection(Request request) {
            try {
                Class<?> clazz = Class.forName(request.getValueType());
                java.util.List<?> keyValues = databaseService.getAllFromCollection(
                    request.getCollectionName(), clazz);
                return Response.success("获取集合所有数据成功", keyValues);
            } catch (ClassNotFoundException e) {
                return Response.error("类型转换失败: " + e.getMessage());
            }
        }
        
        private Response handleClear(Request request) {
            databaseService.clear();
            return Response.success("数据库已清空");
        }
        
        private Response handleGetStatistics(Request request) {
            java.util.Map<String, Object> stats = databaseService.getStatistics();
            return Response.success("获取统计信息成功", stats);
        }
        
        /**
         * 关闭连接
         */
        private void closeConnection() {
            try {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
                if (clientSocket != null) clientSocket.close();
                log.info("客户端 {} 连接已关闭", clientId);
            } catch (IOException e) {
                log.error("关闭客户端 {} 连接失败: error={}", clientId, e.getMessage());
            }
        }
    }
} 